﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.IO;
using System.Xml.Serialization;
using vJine.Core.Base;
using vJine.Core.IO;
using vJine.Core.IO.Xml;
using vJine.Core.IoC.Config;

namespace vJine.Core.ORM {
    /// <summary>
    /// ORM配置类
    /// </summary>
    [Serializable]
    [AppConfig("vJine.Net/OrmConfig")]
    public partial class OrmConfig {
        const string orm_config_file = "./config/vJine.Core.OrmConfig.xml";
        static OrmConfig() {
            try {
                OrmConfig my = null;
                if(File.Exists(OrmConfig.orm_config_file)) {
                    my = new OrmConfig(OrmConfig.orm_config_file);
                } else {
                    my = AppConfig<OrmConfig>.Get() ?? new OrmConfig();
                }
                    
                my.Init();

                OrmConfig._get_My = () => {
                    return my;
                };
            } catch(Exception ex) {
                OrmConfig._get_My = () => {
                    throw new OrmException(ex, "载入配置失败[vJine.Net/OrmConfig]");
                };
            }
        }

        static readonly Call<OrmConfig> _get_My = null;
        /// <summary>
        /// 基于应用程序配置文件的ORM配置类实例
        /// </summary>
        public static OrmConfig My {
            get {
                return _get_My();
            }
        }

        /// <summary>
        /// 实例化ORM配置类
        /// </summary>
        public OrmConfig() {
        }
        /// <summary>
        /// 以指定的配置文件实例化ORM配置类
        /// </summary>
        /// <param name="config_file"></param>
        public OrmConfig(string config_file) {
            XmlHelper.Parse<OrmConfig>(config_file, this, false);
            this.Init();
        }

        /// <summary>
        /// 是否调试
        /// </summary>
        [XmlAttribute]
        public bool debug {
            get;
            set;
        }

        /// <summary>
        /// 是否追踪
        /// </summary>
        [XmlAttribute]
        public bool trace {
            get;
            set;
        }

        /// <summary>
        /// 数据库连接集合
        /// </summary>
        [XmlArray]
        public ConnectionCollection Connections { get; set; }

        /// <summary>
        /// 适配器集合
        /// </summary>
        [XmlArray]
        public AdapterCollection Adapters { get; set; }

        /// <summary>
        /// 转换类集合
        /// </summary>
        [XmlArray]
        public ConverterCollection Converters { get; set; }

        /// <summary>
        /// 全局类型映射集合（必须指定适配器）
        /// </summary>
        [XmlArray]
        public TypeMapCollection TypeMaps { get; set; }

        /// <summary>
        /// 实体映射(必须指定适配器)
        /// </summary>
        [XmlArray]
        public EntityCollection EntityMaps { get; set; }


        Dictionary<Type, Dictionary<Type, Map>> TypeMapIndex =
            new Dictionary<Type, Dictionary<Type, Map>>();

        //AdapterType,ClassType,FieldType,Map
        Dictionary<Type, Dictionary<Type, Dictionary<string, Map>>> SchemaMapIndex = 
            new Dictionary<Type, Dictionary<Type, Dictionary<string, Map>>>();
    }

    public partial class OrmConfig {
        /// <summary>
        /// 数据库连接集合
        /// </summary>
        [Serializable]
        public class ConnectionCollection : CollectionBase<db> {
            /// <summary>
            /// 实例化数据库连接集合
            /// </summary>
            public ConnectionCollection() {
                this.active = true;
            }

            /// <summary>
            /// 是否可用 
            /// </summary>
            [XmlAttribute, ActiveFlag(true)]
            public bool active { get; set; }
            /// <summary>
            /// 依据名字检索数据库连接
            /// </summary>
            /// <param name="name">数据库连接名称</param>
            /// <returns>数据库连接（找不到则返回null）</returns>
            public db this[string name] {
                get {
                    for(int i = 0, len = this.Count; i < len; i++) {
                        db db_i = base[i];

                        if(db_i.name == name && db_i.active) {
                            return db_i;
                        }
                    }

                    return null;
                }
                set {
                    for(int i = 0, len = this.Count; i < len; i++) {
                        if(base[i].name == name) {
                            base[i] = value;
                            return;
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 数据库连接
        /// </summary>
        [Serializable]
        public class db {
            /// <summary>
            /// 实例化数据库连接
            /// </summary>
            public db() {
                this.active = true;
            }

            /// <summary>
            /// 是否可用
            /// </summary>
            [XmlAttribute, ActiveFlag(true)]
            public bool active { get; set; }

            /// <summary>
            /// 数据库连接名称
            /// </summary>
            [XmlAttribute, Map(IsPrimary = true)]
            public string name { get; set; }

            /// <summary>
            /// 表名前缀
            /// </summary>
            [XmlAttribute]
            public string table_prefix { get; set; }

            /// <summary>
            /// 适配器名称（未明确指定时用Adapter.pattern匹配db.name及db.providerName）
            /// </summary>
            [XmlAttribute]
            public string adapter { get; set; }
            /// <summary>
            /// 数据提供者名称
            /// </summary>
            [XmlAttribute]
            public string providerName { get; set; }
            /// <summary>
            /// 主机 {0}
            /// </summary>
            [XmlAttribute]
            public string host { get; set; } //{0}
            /// <summary>
            /// 端口 {1}
            /// </summary>
            [XmlAttribute]
            public string port { get; set; } //{1}
            /// <summary>
            /// 数据提供者类名(当设置providerName时此设置将被忽略，如果指定bin_path则为短名称、否则为长名称)
            /// </summary>
            [XmlElement]
            public string type { get; set; }
            /// <summary>
            /// 数据提供者程序集路径
            /// </summary>
            [XmlElement]
            public string bin_path { get; set; }
            /// <summary>
            /// 用户名 {2}
            /// </summary>
            [XmlElement]
            public string user { get; set; } //{2}
            /// <summary>
            /// 密码 {3}
            /// </summary>
            [XmlElement]
            public string password { get; set; } //{3}
            /// <summary>
            /// 数据库 {4}
            /// </summary>
            [XmlElement]
            public string catalog { get; set; } //{4}
            /// <summary>
            /// 连接字符串(对应于数据提供者,支持string.Format()的形式,可替换参数及索引参见属性说明)
            /// </summary>
            [XmlElement]
            public string connectionString { get; set; }
            

            internal Call<DbProviderFactory> get_Factory;
            internal Call<IDbAdapter> get_Adapter;
        }
        /// <summary>
        /// 适配器集合
        /// </summary>
        [Serializable]
        public class AdapterCollection : Dictionary<string, Adapter> {
            /// <summary>
            /// 实例化适配器集合
            /// </summary>
            public AdapterCollection() {
                this.Active = true;
            }

            /// <summary>
            /// 是否可用
            /// </summary>
            [XmlAttribute, ActiveFlag(true)]
            public bool Active { get; set; }
            /// <summary>
            /// 依据名字检索适配器
            /// </summary>
            /// <param name="name">适配器名称</param>
            /// <returns>数据库适配器（找不到则返回null）</returns>
            public new Adapter this[string name] {
                get {
                    if(string.IsNullOrEmpty(name) || !this.Active) {
                        return null;
                    }

                    Adapter adapter = base[name];
                    Type adapter_type = adapter.type;

                    if(adapter_type == null) {
                        return null;
                    } else if(!adapter_type.IsSubclassOf(typeof(IDbAdapter))) {
                        return null;
                    } else {
                        return adapter;
                    }
                }
                set {
                    if(string.IsNullOrEmpty(name)) {
                        return;
                    }

                    if(base.ContainsKey(name)) {
                        base[name] = value;
                    }
                }
            }
        }
        /// <summary>
        /// 适配器
        /// </summary>
        [Serializable]
        public class Adapter {
            /// <summary>
            /// 将数据库适配器转换为对应的类型
            /// </summary>
            /// <param name="adapter">数据库适配器</param>
            /// <returns>数据库适配器类型</returns>
            public static implicit operator Type(Adapter adapter) {
                if(adapter == null) {
                    return null;
                } else if(adapter.type == null) {
                    return null;
                } else if(!adapter.type.IsSubclassOf(typeof(IDbAdapter))) {
                    return null;
                } else {
                    return adapter.type;
                }
            }
            /// <summary>
            /// 实例化数据库适配器
            /// </summary>
            public Adapter() {
                this.active = true;
            }
            /// <summary>
            /// 是否可用
            /// </summary>
            [XmlAttribute, ActiveFlag(true)]
            public bool active { get; set; }
            /// <summary>
            /// 适配器名称
            /// </summary>
            [XmlAttribute, Map(IsPrimary=true)]
            public string name { get; set; }
            /// <summary>
            /// 匹配模式（未明确指定db.adapter时用以匹配db.name及db.providerName）
            /// </summary>
            [XmlAttribute]
            public string pattern { get; set; }
            /// <summary>
            /// 适配器类
            /// </summary>
            [XmlElement]
            public Type type { get; set; }
            /// <summary>
            /// 数据库提供者(如果db.providerName为空，则被设置为改值)
            /// </summary>
            [XmlAttribute]
            public string providerName { get; set; }
            /// <summary>
            /// 连接字符串(如果db.connectionString为空，则被设置为该值)
            /// </summary>
            [XmlElement]
            public string connectionString { get; set; }
        }
        /// <summary>
        /// 转换器类集合
        /// </summary>
        [Serializable]
        public class ConverterCollection : Dictionary<string, Converter> {
            /// <summary>
            /// 实例化转换器类集合
            /// </summary>
            public ConverterCollection() {
                this.active = true;
            }
            /// <summary>
            /// 依据名称检索转换器实例
            /// </summary>
            /// <param name="name">转换器名称</param>
            /// <returns>转换器实例</returns>
            public new Converter this[string name] {
                get {
                    if(string.IsNullOrEmpty(name)) {
                        return null;
                    } else if(!this.active || base.Count == 0) {
                        return null;
                    } else if(!base.ContainsKey(name)) {
                        return null;
                    } else {
                        return base[name];
                    }
                }
                set {
                    if(string.IsNullOrEmpty(name)) {
                        return;
                    } else if(!base.ContainsKey(name)) {
                        return;
                    } else {
                        base[name] = value;
                    }
                }
            }

            /// <summary>
            /// 是否可用
            /// </summary>
            [XmlAttribute, ActiveFlag(true)]
            public bool active { get; set; }
        }

        /// <summary>
        /// 转换器类
        /// </summary>
        [Serializable]
        public class Converter {
            /// <summary>
            /// 将转换器类转换为转换器类型
            /// </summary>
            /// <param name="conv">转换类实例</param>
            /// <returns>转换类对应的类型</returns>
            public static implicit operator Type(Converter conv) {
                if(conv == null) {
                    return null;
                } else if(!conv.active) {
                    return null;
                } else if(conv.type == null) {
                    return null;
                } else {
                    return conv.type;
                }
            }
            /// <summary>
            /// 实例化转换器类
            /// </summary>
            public Converter() {
                this.active = true;
            }
            /// <summary>
            /// 是否可用
            /// </summary>
            [XmlAttribute, ActiveFlag(true)]
            public bool active { get; set; }
            /// <summary>
            /// 转换器名称
            /// </summary>
            [XmlAttribute, Map(IsPrimary = true)]
            public string name { get; set; }
            /// <summary>
            /// 转换器类型
            /// </summary>
            [XmlAttribute]
            public Type type { get; set; }
        }

        /// <summary>
        /// 全局类型映射集合
        /// </summary>
        [Serializable]
        public class TypeMapCollection : CollectionBase<Map> {
            /// <summary>
            /// 实例化全局类型映射集合
            /// </summary>
            public TypeMapCollection() {
                this.Active = true;
            }

            /// <summary>
            /// 是否可用
            /// </summary>
            [XmlAttribute, ActiveFlag(true)]
            public bool Active { get; set; }

            /// <summary>
            /// 适配器名称(如果Map.adapter未设置时取该值)
            /// </summary>
            [XmlAttribute]
            public string adapter { get; set; }
        }

        /// <summary>
        /// 实体类型映射集合
        /// </summary>
        [Serializable]
        public class EntityCollection : CollectionBase<Entity> {
            /// <summary>
            /// 实例化实体类型映射集合
            /// </summary>
            public EntityCollection() {
                this.Active = true;
            }
            /// <summary>
            /// 是否可用
            /// </summary>
            [XmlAttribute, ActiveFlag(true)]
            public bool Active { get; set; }
            /// <summary>
            /// 适配器名称(如果Entity.adapter未设置时取该值)
            /// </summary>
            [XmlAttribute]
            public string adapter { get; set; }
        }

        /// <summary>
        /// 实体类型
        /// </summary>
        [Serializable]
        public class Entity : CollectionBase<Map> {
            /// <summary>
            /// 实例化实体类型映射
            /// </summary>
            public Entity() {
                this.active = true;
            }
            /// <summary>
            /// 是否可用
            /// </summary>
            [XmlAttribute, ActiveFlag(true)]
            public bool active { get; set; }
            /// <summary>
            /// 适配器名称
            /// </summary>
            [XmlAttribute]
            public string adapter { get; set; }
            /// <summary>
            /// 实体类型
            /// </summary>
            [XmlAttribute]
            public Type type { get; set; }
        }

        /// <summary>
        /// 类型映射
        /// </summary>
        [Serializable]
        public class Map {
            /// <summary>
            /// 将类型映射转换为特性映射
            /// </summary>
            /// <param name="map">类型映射</param>
            /// <returns>类型映射特性</returns>
            public static implicit operator MapAttribute(OrmConfig.Map map) {
                return new MapAttribute() {
                    Name = map.Name, Alias = map.Alias
                    , IsPrimary = map.IsPrimary == null ? false : map.IsPrimary.Value, UniqueName = map.UniqueName
                    , IsNullable = map.IsNullable == null ? false : map.IsNullable.Value
                    , IsIgnored = map.IsIgnored == null ? false : map.IsIgnored.Value, TrimString = map.TrimString == null ? false : map.TrimString.Value
                    , SQL_TYPE = map.SQL_TYPE, DbType = map.DbType
                    , Conv = map.Conv as Type
                };
            }
            /// <summary>
            /// 实例化配置文件类型映射
            /// </summary>
            public Map() {
                this.active = true;
            }
            /// <summary>
            /// Adapter名称，对应于Adapters#Adapter.name
            /// </summary>
            [XmlAttribute]
            public string adapter { get; set; }

            /// <summary>
            /// 是否有效，若标记为False则或略该映射
            /// </summary>
            [XmlAttribute, ActiveFlag(true)]
            public bool active { get; set; }
            
            /// <summary>
            /// 属性类型（仅用于TypeMaps.Map配置）
            /// </summary>
            [XmlAttribute]
            public Type type { get; set; }

            /// <summary>
            /// 属性名（仅用于Entity.Map配置）
            /// </summary>
            [XmlAttribute]
            public string Name { get; set; }
            /// <summary>
            /// 属性别名
            /// </summary>
            [XmlAttribute]
            public string Alias { get; set; }
            /// <summary>
            /// 数据库SQL类型
            /// </summary>
            [XmlAttribute]
            public string SQL_TYPE { get; set; }
            /// <summary>
            /// 数据库命令参数类型
            /// </summary>
            [XmlAttribute]
            public DbType? DbType { get; set; }
            /// <summary>
            /// 类型转换类名称（对应于Converts#Converter.name）
            /// </summary>
            [XmlAttribute]
            public object Conv { get; set; }
            /// <summary>
            /// 是否主键
            /// </summary>
            [XmlAttribute]
            public bool ?IsPrimary { get; set; }
            /// <summary>
            /// 唯一键名称
            /// </summary>
            [XmlAttribute]
            public string UniqueName { get; set; }
            /// <summary>
            /// 是否可空
            /// </summary>
            [XmlAttribute]
            public bool? IsNullable { get; set; }
            /// <summary>
            /// 是否忽略该属性的数据库操作
            /// </summary>
            [XmlAttribute]
            public bool? IsIgnored { get; set; }
            /// <summary>
            /// 是否Trim字符串(移除定长字符串的首尾空白字符，对于非字符串属性无效)
            /// </summary>
            [XmlAttribute]
            public bool? TrimString { get; set; }
        }
    }
}
